# import * from pygame
# from pygame import *
import pygame
import traceback
import sys
from pygame.locals import *
from random import *
import myPlane
import enemy
import bullet
import apply

# 保存变量
mixer = pygame.mixer
mix_music = mixer.music
mix_sound = mixer.Sound

# 两个初始化
pygame.init()
mixer.init()

# 设置背景尺寸， 标题
bg_size = width,height = 480,700
screen = pygame.display.set_mode(bg_size)
pygame.display.set_caption("飞机大战")

# 加载游戏背景，不透明 使用 convert
background =  pygame.image.load("images/background.png").convert()

# 加载音乐
mix_music.load("sound/game_music.ogg")
mix_music.set_volume(0.2)

bullet_sound = mix_sound("sound/bullet.wav")
bullet_sound.set_volume(0.2)

bomb_sound = mix_sound("sound/use_bomb.wav")
bomb_sound.set_volume(0.2)

supply_sound = mix_sound("sound/supply.wav")
supply_sound.set_volume(0.2)

get_bomb_sound = mix_sound("sound/get_bomb.wav")
get_bomb_sound.set_volume(0.2)

get_bullet_sound = mix_sound("sound/get_bullet.wav")
get_bullet_sound.set_volume(0.2)

upgrade_sound = mix_sound("sound/upgrade.wav")
upgrade_sound.set_volume(0.2)

enemy3_fly_sound = mix_sound("sound/enemy3_flying.wav")
enemy3_fly_sound.set_volume(0.2)

enemy1_down_sound = mix_sound("sound/enemy1_down.wav")
enemy1_down_sound.set_volume(0.2)

enemy2_down_sound = mix_sound("sound/enemy2_down.wav")
enemy2_down_sound.set_volume(0.2)

enemy3_down_sound = mix_sound("sound/enemy3_down.wav")
enemy3_down_sound.set_volume(0.5)

me_down_sound = mix_sound("sound/me_down.wav")
me_down_sound.set_volume(0.2)


# 颜色常量
BLACK=(0,0,0)
GRENN=(0,255,0)
RED=(255,0,0)
WHITE=(255,255,255)

# 增加小型敌机
def add_small_enemies(g1,g2,num):

    for i in range(num):
        e1 = enemy.SmallEmemy(bg_size)
        g1.add(e1)
        g2.add(e1)

# 增加中型敌机
def add_mid_enemies(g1,g2,num):

    for i in range(num):
        e1 = enemy.MediumEmemy(bg_size)
        g1.add(e1)
        g2.add(e1)

# 增加大型敌机
def add_large_enemies(g1,g2,num):

    for i in range(num):
        e1 = enemy.LargeEmemy(bg_size)
        g1.add(e1)
        g2.add(e1)

# 提升速度
def incr_speed(target,speed):

    for e in target:
        e.speed += speed

# 更新子弹的速度
def updateBulletPos(me,speed_group,isSuper=False):

    if isSuper:
        speed_group[0] =  (me.rect.left,me.rect.centery)
        speed_group[1] = (me.rect.centerx-33,me.rect.centery)
        speed_group[2] = me.rect.midtop
        speed_group[3] = (me.rect.centerx+33,me.rect.centery)
        speed_group[4] =  (me.rect.right,me.rect.centery)
    else:
        speed_group[0] = me.rect.midtop


def exitGame():

    pygame.quit()
    sys.exit()


def  main():
    
    # 播放音乐,循环播放
    mix_music.play(-1)

    # 设置帧率
    clock = pygame.time.Clock()
    
    # 设置初识分数
    score = 0
    score_font = pygame.font.Font("font/font.ttf",36)

    # 设置初始登记
    currentLevel = 1

    # 是否暂停
    isPause= False

    # 是否正在运行
    running = True

    # 精灵图片切换
    switch_img = True

    # 延迟变量，用于延迟 飞机图片切换速度
    frequency_count = frequency=100

    # 生成飞机
    me =  myPlane.MyPlane(bg_size)
    me_live = pygame.image.load("images/life.png").convert_alpha()
    me_live_rect = me_live.get_rect()


    # # # # # # # # # # # # # # # # # # # # 
    # 保存所有敌机
    # # # # # # # # # # # # # # # # # # # # 
    enemies = pygame.sprite.Group()
    
    LM_over_index=0
    MD_over_index=0
    SM_over_index=0
    plane_over_index=0

    # 小敌机组
    small_ememies = pygame.sprite.Group()
    add_small_enemies(small_ememies,enemies,15)

    # 中敌机组
    mid_ememies = pygame.sprite.Group()
    add_mid_enemies(mid_ememies,enemies,8)

    # 大敌机组
    large_ememies = pygame.sprite.Group()
    add_large_enemies(large_ememies,enemies,3)
    


    # # # # # # # # # # # # # # # # # # # # 
    # 按钮,暂停,重新开始，退出游戏
    # # # # # # # # # # # # # # # # # # # # 
    pause_off = pygame.image.load("images/pause_nor.png").convert_alpha()
    pause_off_active = pygame.image.load("images/pause_pressed.png").convert_alpha()
    pause_on= pygame.image.load("images/resume_nor.png").convert_alpha()
    pause_on_active= pygame.image.load("images/resume_pressed.png").convert_alpha()

    currentPause = pause_on
    currentPauseRect  = currentPause.get_rect()
    currentPauseRect.left,currentPauseRect.top = width - currentPauseRect.width - 10 ,10

    resetBtn = pygame.image.load("images/again.png").convert_alpha()
    exitBtn = pygame.image.load("images/gameover.png").convert_alpha()

    resetBtn_rect = resetBtn.get_rect()
    exitBtn_rect = exitBtn.get_rect()

    resetBtn_pos= ( (bg_size[0]-resetBtn_rect.width)/2, (bg_size[1]-resetBtn_rect.height)/2 + 60 )

    resetBtn_rect.left,resetBtn_rect.top = resetBtn_pos[0],resetBtn_pos[1]

    exitBtn_rect.left,exitBtn_rect.top = resetBtn_pos[0], resetBtn_pos[1]+10+ resetBtn_rect.height

    isOnOverPage = False


    # # # # # # # # # # # # # # # # # # # # 
    # 子弹
    # # # # # # # # # # # # # # # # # # # # 

    SUPER_BULLET_TIME= USEREVENT+1 # 增加自定义事件
    is_use_double_bullet = False # 是否使用超级子弹

    # 普通子弹
    bullets_normal=[]
    bullets_normal_index= 0
    bullets_normal_num=4
    bullets_normal_pos=[me.rect.midtop]
    for item in range(bullets_normal_num):
        bullets_normal.append(bullet.Bullect_normal(bullets_normal_pos[0]))

    # 超级子弹
    bullects_super=[]
    bullects_super_index= 0
    bullects_super_num=4*5
    bullets_super_pos=[
        (me.rect.left,me.rect.centery),
        (me.rect.centerx-33,me.rect.centery),
        me.rect.midtop,
        (me.rect.centerx+33,me.rect.centery),
        (me.rect.right,me.rect.centery)
    ]

    # print("bullects_super_num/5",bullects_super_num/5)

    for item in range(int(bullects_super_num/5)):
        for sp in bullets_super_pos:
            bullects_super.append(bullet.Bullect_super(sp))

    # 当前的子弹
    currentBullect=bullets_normal
    currentBullectIndex=bullets_normal_index
    currentBullectNum=bullets_normal_num
    currentBullectPos = bullets_normal_pos # 子弹的位置

    # # # # # # # # # # # # # # # # # # # # 
    # 炸弹
    # # # # # # # # # # # # # # # # # # # # 
    bomb_image = pygame.image.load("images/bomb.png")
    bomb_rect = bomb_image.get_rect()
    bomb_rect.left,bomb_rect.top = 10,height - bomb_rect.height -10
    bomb_font= pygame.font.Font("font/font.ttf",48)
    bomb_num = 3
    

    # # # # # # # # # # # # # # # # # # # # 
    # 补给包
    # # # # # # # # # # # # # # # # # # # # 
    bullet_supply = apply.BulletApply(bg_size)
    bomb_supply = apply.BombApply(bg_size)
    SUPPLY_TIME= USEREVENT

    # 设置定时器，事件通知，每30秒通知一次事件
    pygame.time.set_timer(SUPPLY_TIME,30*1000)


    while running:

        me_currentLive = me.currentLives

        if not me_currentLive:
            isPause = True

        # isPause = not(me_currentLive) or isPause

        if isPause:

            currentPause = pause_on

            # 取消自定义事件
            pygame.time.set_timer(SUPPLY_TIME,0)

            # 暂停所有音效，因为大敌机出来的时候，音效是循环播放的，如果不暂停，会一直播放
            mixer.pause()

            # 暂停背景音乐
            mix_music.pause()

        else:
            currentPause = pause_off

        # 渲染背景
        screen.blit(background,(0,0))

        # # # # # # # # # # # # # # # # # # # # # # # # # 
        # 事件捕捉
        # # # # # # # # # # # # # # # # # # # # # # # # # 
        for e in pygame.event.get():

            # QUIT 使用要导入常量模块
            if e.type==QUIT:
                exitGame()

            # 点击事件
            elif e.type ==MOUSEBUTTONDOWN:

                if e.button==1: 

                    # 暂停
                    if currentPauseRect.collidepoint(e.pos):

                        isPause = not isPause

                        if not isPause:
                
                            # 自定义事件
                            pygame.time.set_timer(SUPPLY_TIME,30*1000)

                            # 重放所有音效，因为大敌机出来的时候，音效是循环播放的，如果不暂停，会一直播放
                            mixer.unpause()

                            # 重放背景音乐
                            mix_music.unpause()

            # hover 事件
            elif e.type==MOUSEMOTION:
                
                if currentPauseRect.collidepoint(e.pos):
                    if isPause:
                        currentPause = pause_on_active
                    else:
                        currentPause = pause_off_active

            # 键盘
            elif e.type==KEYDOWN:
                if e.key==K_SPACE:
                    if bomb_num:
                        
                        bomb_num-=1
                        for e in enemies:
                            if e.rect.bottom>0:
                                
                                if e in mid_ememies:
                                    score+=20
                                elif e in large_ememies:
                                    score+=30
                                else:
                                    score+=10
                                e.actived = False

            # 自定义事件 - 补给事件
            elif e.type==SUPPLY_TIME:
                supply_sound.play()

                if choice([True,False]):
                    bullet_supply.reset()

                else:
                    bomb_supply.reset()

            # 自定义事件 - 超级子弹事件
            elif e.type==SUPER_BULLET_TIME:

                is_use_double_bullet=False

                pass


        # # # # # # # # # # # # # # # # # # # # # # # # # 
        # 根据用户分数来提升难度
        # # # # # # # # # # # # # # # # # # # # # # # # # 

        # 第二关
        if currentLevel ==1 and score>500:

            currentLevel = 2
            upgrade_sound.play()

            add_small_enemies(small_ememies,enemies,5)
            add_mid_enemies(mid_ememies,enemies,2)
            add_large_enemies(large_ememies,enemies,1)

            # 提升小型敌机的速度
            incr_speed(small_ememies,1)

        # 第三关
        elif currentLevel==2 and score>2000:
            
            currentLevel = 3
            upgrade_sound.play()

            add_small_enemies(small_ememies,enemies,8)
            add_mid_enemies(mid_ememies,enemies,4)
            add_large_enemies(large_ememies,enemies,2)

            # 提升小型敌机的速度
            # incr_speed(small_ememies,1)
            incr_speed(mid_ememies,1)

        # 第四关
        elif currentLevel==3 and score>5000:
            
            currentLevel = 4
            upgrade_sound.play()

            add_small_enemies(small_ememies,enemies,8)
            add_mid_enemies(mid_ememies,enemies,5)
            add_large_enemies(large_ememies,enemies,3)

            # 提升小型敌机的速度
            incr_speed(small_ememies,1)
            # incr_speed(mid_ememies,1)

        # 第五关
        elif currentLevel==4 and score>10000:
            
            currentLevel = 5
            upgrade_sound.play()

            add_small_enemies(small_ememies,enemies,8)
            add_mid_enemies(mid_ememies,enemies,4)
            add_large_enemies(large_ememies,enemies,2)

            # 提升小型敌机的速度
            incr_speed(small_ememies,1)
            incr_speed(mid_ememies,1)


        # 游戏暂停，或者 飞机没有生命之后
        if not(isPause) :

            # # # # # # # # # # # # # # # # # # # # # # # # # 
            # 检测键盘被按下
            # # # # # # # # # # # # # # # # # # # # # # # # # 
            key_pressed = pygame.key.get_pressed()

            if key_pressed[K_w] or  key_pressed[K_UP]:
                me.move_up()
            if key_pressed[K_s] or  key_pressed[K_DOWN]:
                me.move_down()
            if key_pressed[K_a] or  key_pressed[K_LEFT]:
                me.move_left()
            if key_pressed[K_d] or  key_pressed[K_RIGHT]:
                me.move_right()

            frequency-=1

            if not(frequency % 5 ):
                switch_img= not switch_img

            if not frequency:
                frequency = frequency_count


            # # # # # # # # # # # # # # # # # # # # # # # # # 
            # 绘制敌人
            # # # # # # # # # # # # # # # # # # # # # # # # # 
            
            # 绘制大敌机
            for LM in large_ememies:

                LM.move()

                if LM.actived:
                    if LM.is_hit:
                        screen.blit(LM.hit_img,LM.rect)
                        LM.is_hit=False
                    else:
                        if switch_img:
                            screen.blit(LM.image,LM.rect)
                        else:
                            screen.blit(LM.image2,LM.rect)
                    
                    # 绘制血槽 , 2 是宽度
                    pygame.draw.line(screen,BLACK,(LM.rect.left, LM.rect.top-5),(LM.rect.right, LM.rect.top-5),2)

                    # 血槽颜色要变化
                    currentLive = LM.currentLive/ LM.lives

                    if currentLive>0.5:
                        live_color= GRENN
                    else :
                        live_color= RED

                    pygame.draw.line(screen,live_color,(LM.rect.left,LM.rect.top-5),(LM.rect.left+LM.rect.width*currentLive,
                        LM.rect.top-5),2)

                    # 即将出现在画面中，播放音效
                    if LM.rect.bottom == -50:
                        enemy3_fly_sound.play(-1)

                else:

                    if not(frequency % 3):
                        
                        if LM_over_index == 0:
                            enemy3_fly_sound.stop()
                            enemy3_down_sound.play()

                        screen.blit(LM.over_img[LM_over_index],LM.rect)
                        LM_over_index = (LM_over_index+1)%6

                        if LM_over_index==0:
                            LM.reset()

            # 绘制中敌机
            for MM in mid_ememies:
                MM.move()

                if MM.actived:
                    
                    if MM.is_hit:
                        screen.blit(MM.hit_img,MM.rect)
                        MM.is_hit=False
                    else:
                        screen.blit(MM.image,MM.rect)

                    # 绘制血槽 , 2 是宽度
                    pygame.draw.line(screen,BLACK,(MM.rect.left, MM.rect.top-5),(MM.rect.right, MM.rect.top-5),2)

                    # 血槽颜色要变化
                    currentLive = MM.currentLive/ MM.lives

                    if currentLive>0.5:
                        live_color= GRENN
                    else :
                        live_color= RED

                    pygame.draw.line(screen,live_color,(MM.rect.left,MM.rect.top-5),(MM.rect.left+MM.rect.width*currentLive,
                        MM.rect.top-5),2)

                else:
                    if not(frequency % 3):
                        
                        if MD_over_index == 0:
                            enemy2_down_sound.play()

                        screen.blit(MM.over_img[MD_over_index],MM.rect)
                        MD_over_index = (MD_over_index+1)%4

                        if MD_over_index==0:
                            MM.reset()

            # 绘制小敌机
            for SM in small_ememies:
                SM.move()
                if SM.actived:
                    screen.blit(SM.image,SM.rect)
                else:
                    if not(frequency % 3):
                        
                        if SM_over_index == 0:
                            enemy1_down_sound.play()

                        screen.blit(SM.over_img[SM_over_index],SM.rect)
                        SM_over_index = (SM_over_index+1)%4

                        if SM_over_index==0:
                            SM.reset()


            # # # # # # # # # # # # # # # # # # # # # # # # # 
            # 绘制子弹
            # 必须是 10 的倍数才往下走
            # # # # # # # # # # # # # # # # # # # # # # # # # 
            
            # 检测当前是需要什么子弹
            if is_use_double_bullet:
                currentBullect = bullects_super
                currentBullectIndex = bullects_super_index
                currentBullectNum = bullects_super_num
                updateBulletPos(me,bullets_super_pos,True)
                
                currentBullectPos=bullets_super_pos
            else:
                currentBullect = bullets_normal
                currentBullectIndex = bullets_normal_index
                currentBullectNum = bullets_normal_num
                updateBulletPos(me,bullets_normal_pos)
                
                currentBullectPos=bullets_normal_pos

            # 这一段还是不太懂什么意思
            if not( frequency % 10):
                bullet_sound.play()

                for item in currentBullectPos:
                    currentBullect[currentBullectIndex].reset(item)
                    currentBullectIndex = (currentBullectIndex + 1) % currentBullectNum


                # item = bullets[bullet1_index]
                # bullet1_index= (bullet1_index+1)%bullet_num
                # screen.blit(item.image,item.rect)
                # item.move(e.rect.midtop)

            # 检测子弹碰撞
            for index,item in enumerate(currentBullect):

                # 子弹有效，才检测是否碰撞
                if item.actived:
                    
                    screen.blit(item.image,item.rect)

                    bullet_index = index % len(currentBullectPos)

                    # for speed in currentBullectPos:
 
                    # print("spped--->",speed)

                    item.move(currentBullectPos[bullet_index])

                    enemies_over = pygame.sprite.spritecollide(item, enemies, False, pygame.sprite.collide_mask)

                    if enemies_over: 

                        item.reset(currentBullectPos[bullet_index])
                        
                        for e in enemies_over:

                            if e in mid_ememies or e in large_ememies:

                                e.currentLive -=1
                                e.is_hit=True

                                if e.currentLive==0:
                                    e.actived=False
                                    
                                    if e in mid_ememies:
                                        score+=20
                                    elif e in large_ememies:
                                        score+=30

                            else:
                                score+=10
                                e.actived = False

                
            # # # # # # # # # # # # # # # # # # # # # # # # # 
            # 检测我方飞机是否和 敌机碰撞
            # # # # # # # # # # # # # # # # # # # # # # # # # 
            enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)

            if enemies_down:
                
                for e in enemies_down:
                    if e.actived and me.actived:
                        me.actived = False
                        # print("me-->",me)
                        if me.currentLives:
                            me.currentLives-=1
                        else:
                            print("game over")
                        
                        e.actived = False


            # # # # # # # # # # # # # # # # # # # # # # # # # 
            # 绘制飞机
            # # # # # # # # # # # # # # # # # # # # # # # # # 
            if me.actived:
                if switch_img:
                    screen.blit(me.image,me.rect)
                else:
                    screen.blit(me.image2,me.rect)
            else:
                if not(frequency%3):

                    if plane_over_index==0:
                        me_down_sound.play()
                    
                    screen.blit(me.over_img[plane_over_index],me.rect)
                    plane_over_index = (plane_over_index+1)%4

                    if plane_over_index==0:
                        me.reset()

            # # # # # # # # # # # # # # # # # # # # # # # # # 
            # 绘制补给包
            # # # # # # # # # # # # # # # # # # # # # # # # # 
            
            # 炸弹移动，并且检测是否被拿了
            if bomb_supply.actived:
                bomb_supply.move()
                screen.blit(bomb_supply.image,bomb_supply.rect)

                if pygame.sprite.collide_mask(bomb_supply, me):
                    get_bomb_sound.play()
                    bomb_num+=3
                    bomb_supply.actived=False

            # 超级子弹包移动，并且检测是否被拿了
            if bullet_supply.actived:
                bullet_supply.move()
                screen.blit(bullet_supply.image,bullet_supply.rect)

                if pygame.sprite.collide_mask(bullet_supply, me):

                    get_bullet_sound.play()
                    bullet_supply.actived=False
                    is_use_double_bullet = True

                    pygame.time.set_timer(SUPER_BULLET_TIME,30*1000)

        elif not(me_currentLive):

            reset_height = resetBtn_rect.height

            # 当前分数
            current_score = score_font.render(u" Your Score: %s" % str(score),True,WHITE)
            current_score_rect = current_score.get_rect()
            screen.blit(current_score,((bg_size[0] - current_score_rect.width)/2,resetBtn_pos[1]-reset_height-40))

            # 重新开始
            screen.blit(resetBtn,resetBtn_rect)

            # 退出游戏
            screen.blit(exitBtn,exitBtn_rect)

            if not(isOnOverPage):

                # 读取历史高分
                with open("record.txt","r") as f:

                    # 转成数字，因为需要比较
                    history_score_highest = f.read()

                    # print("history_score_highest",not history_score_highest,history_score_highest)

                    if not(history_score_highest):
                        history_score_highest =0

                with open("record.txt","w") as f:

                    if int(history_score_highest)<score :
                        f.write(str(score))

                # print("history_score_highest",history_score_highest,score,history_score_highest<score)

                # 打破历史高分，存档
                
                
                isOnOverPage = True

            # 显示历史高分
            history_score_highest_text = score_font.render(u"Highest Score: %s" % str(history_score_highest),True,WHITE)
            screen.blit(history_score_highest_text,(20,20))

            # 检测事件
            if pygame.mouse.get_pressed()[0]:

                mouse_pos = pygame.mouse.get_pos()

                pos_x = mouse_pos[0]
                pos_y = mouse_pos[1]

                # 重新开始
                if resetBtn_rect.left < pos_x < resetBtn_rect.right and  \
                   resetBtn_rect.top <pos_y < resetBtn_rect.bottom:

                   main()

                # 结束游戏
                elif exitBtn_rect.left < pos_x < exitBtn_rect.right and  \
                   exitBtn_rect.top <pos_y < exitBtn_rect.bottom:
                    exitGame()

        # 结束页面不绘制下面信息
        if not isOnOverPage:

            # 渲染分数
            score_text = score_font.render("Score: %s" % str(score),True,WHITE)
            screen.blit(score_text,(10,5))

            # 渲染暂停键
            screen.blit(currentPause,currentPauseRect)

            # 全屏炸弹
            screen.blit(bomb_image,bomb_rect)
            bomb_num_text = bomb_font.render("× %s" % str(bomb_num),True,WHITE)
            screen.blit(bomb_num_text,(bomb_rect.left+bomb_rect.width+10,bomb_rect.top))

            # 飞机剩下多少生命
            if me_currentLive:
                for i in range(me_currentLive):
                    screen.blit(me_live,(bg_size[0] - me_live_rect.width*(i+1) -10, bg_size[1]-me_live_rect.height - 10))

        # 界面翻转过来
        pygame.display.flip()
        clock.tick(60)



if __name__=="__main__":

    try:
        main()

    except SystemExit:
        pass

    except:

        print("其他错误")
        traceback.print_exc()
        pygame.quit()
        input()


